#include "SQLTableSourceImpl.h"

#include "../../../utils/FnvHash.h"
#include "../../../utils/StringUtils.h"
#include "../../../utils/ifeq.h"
#include "../../SQLUtils.h"
#include "SQLColumnDefinition.h"

SQLTableSourceImpl::SQLTableSourceImpl()
{
  hints = std::make_shared<std::list<SQLHint_ptr>>();
}

SQLTableSourceImpl::SQLTableSourceImpl(string_ptr alias)
{
  this->alias = alias;
  hints = std::make_shared<std::list<SQLHint_ptr>>();
}

string_ptr SQLTableSourceImpl::getAlias()
{
  return this->alias;
}

string_ptr SQLTableSourceImpl::getAlias2()
{
  if (this->alias->empty())
  {
    return alias;
  }

  char first = alias->at(0);
  if (first == '"' || first == '\'')
  {
    // char[] chars = new char[alias->length() - 2];
    string_ptr chars;
    int len = 0;
    for (int i = 1; i < alias->length() - 1; ++i)
    {
      char ch = alias->at(i);
      if (ch == '\\')
      {
        ++i;
        ch = alias->at(i);
      }
      chars->append(StringUtils::charToString(ch));
    }
    return chars;
  }

  return alias;
}

void SQLTableSourceImpl::setAlias(string_ptr alias)
{
  this->alias = alias;
  this->aliasHashCode64_ = 0L;
}

int SQLTableSourceImpl::getHintsSize()
{
  if (hints->empty())
  {
    return 0;
  }

  return hints->size();
}

SQLHint_list_ptr SQLTableSourceImpl::getHints()
{
  // if (hints == NULL) {
  //     hints = new ArrayList<SQLHint*>(2);
  // }
  return hints;
}

void SQLTableSourceImpl::setHints(SQLHint_list_ptr hints)
{
  this->hints = hints;
}

SQLObject_ptr SQLTableSourceImpl::clone()
{
  SQLObject_ptr clone_tmp = SharedObject(SQLTableSourceImpl);
  std::shared_ptr<SQLTableSourceImpl> clone_res = std::dynamic_pointer_cast<SQLTableSourceImpl>(clone_tmp);

  return clone_res;
}

string_ptr SQLTableSourceImpl::computeAlias()
{
  return alias;
}

SQLExpr_ptr SQLTableSourceImpl::getFlashback()
{
  return flashback;
}

void SQLTableSourceImpl::setFlashback(SQLExpr_ptr flashback)
{
  if (flashback != NULL)
  {
    // flashback->setParent(this);
  }
  this->flashback = flashback;
}

BOOL_ptr SQLTableSourceImpl::containsAlias(string_ptr alias)
{
  if (SQLUtils::nameEquals(this->alias, alias))
  {
    return BOOL::TRUE;
  }

  return BOOL::FALSE;
}

long SQLTableSourceImpl::aliasHashCode64()
{
  if (aliasHashCode64_ == 0 && !alias->empty())
  {
    aliasHashCode64_ = FnvHash::hashCode64(alias);
  }
  return aliasHashCode64_;
}

SQLColumnDefinition_ptr SQLTableSourceImpl::findColumn(string_ptr columnName)
{
  if (columnName == nullptr)
  {
    return nullptr;
  }

  long hash = FnvHash::hashCode64(columnName);
  return findColumn(hash);
}

SQLColumnDefinition_ptr SQLTableSourceImpl::findColumn(long columnNameHash)
{
  return nullptr;
}

SQLObject_ptr SQLTableSourceImpl::resolveColum(long columnNameHash)
{
  return std::dynamic_pointer_cast<SQLObject>(findColumn(columnNameHash));
}

SQLTableSource_ptr SQLTableSourceImpl::findTableSourceWithColumn(string_ptr columnName)
{
  if (columnName->empty())
  {
    return NULL;
  }

  long hash = FnvHash::hashCode64(columnName);
  return findTableSourceWithColumn(hash, columnName, 0);
}

SQLTableSource_ptr SQLTableSourceImpl::findTableSourceWithColumn(SQLName_ptr columnName)
{
  // if (columnName instanceof SQLIdentifierExpr) {
  //     return findTableSourceWithColumn(
  //             columnName->nameHashCode64(), columnName->getSimpleName(), 0);
  // }

  // if (columnName instanceof SQLPropertyExpr) {
  //     SQLExpr_ptr owner = ((SQLPropertyExpr) columnName)->getOwner();
  //     if (owner instanceof SQLIdentifierExpr) {
  //         return findTableSource(((SQLIdentifierExpr) owner)->nameHashCode64());
  //     }
  // }

  return NULL;
}

SQLTableSource_ptr SQLTableSourceImpl::findTableSourceWithColumn(long columnNameHash)
{
  return findTableSourceWithColumn(columnNameHash, NULL, 0);
}

SQLTableSource_ptr SQLTableSourceImpl::findTableSourceWithColumn(long columnNameHash, string_ptr columnName, int option)
{
  return NULL;
}

SQLTableSource_ptr SQLTableSourceImpl::findTableSource(string_ptr alias)
{
  long hash = FnvHash::hashCode64(alias);
  return findTableSource(hash);
}

SQLTableSource_ptr SQLTableSourceImpl::findTableSource(long alias_hash)
{
  long hash = this->aliasHashCode64();
  if (hash != 0 && hash == alias_hash)
  {
    return SharedObject(SQLTableSourceImpl);
  }
  return NULL;
}

bool SQLTableSourceImpl::equals(Object_ptr o)
{
  if (this == o.get())
  {
    return true;
  }
  if (o == NULL || getClass() != o->getClass())
  {
    return false;
  }

  std::shared_ptr<SQLTableSourceImpl> that = std::dynamic_pointer_cast<SQLTableSourceImpl>(o);

  if (aliasHashCode64() != that->aliasHashCode64())
  {
    return false;
  }
  if (hints != NULL ? !IFEQ::ifeq<SQLHint_ptr>(hints,that->hints) : that->hints != NULL) {
      return false;
  }
  return flashback != NULL ? flashback == that->flashback : that->flashback == NULL;
}

int SQLTableSourceImpl::hashCode()
{
  // int result = (hints != NULL ? hints->hashCode() : 0);
  int result = 0;
  result = 31 * result + (flashback != NULL ? flashback->hashCode() : 0);
  result = 31 * result + (int)(aliasHashCode64() ^ (aliasHashCode64() >> 32));
  return result;
}

SQLPivot_ptr SQLTableSourceImpl::getPivot()
{
  return pivot;
}

void SQLTableSourceImpl::setPivot(SQLPivot_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLTableSourceImpl));
  }
  this->pivot = x;
}

SQLUnpivot_ptr SQLTableSourceImpl::getUnpivot()
{
  return unpivot;
}

void SQLTableSourceImpl::setUnpivot(SQLUnpivot_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLTableSourceImpl));
  }
  this->unpivot = x;
}
